#include "Utilities.h"

HWND Utilities::HProgMan=0;
HWND Utilities::HSHELLDLL_DefViewParent=0;
HWND Utilities::HSHELLDLL_DefView=0;
HWND Utilities::HSysListView32=0;

HWND Utilities::GetDesktopWindow(DesktopWindow desktopWindow)
{
	 HProgMan = GetShellWindow();
	 HSHELLDLL_DefViewParent = HProgMan;
	 HSHELLDLL_DefView = FindWindowEx(HProgMan, 0, TEXT("SHELLDLL_DefView"), 0);
	 HSysListView32 = FindWindowEx(HSHELLDLL_DefView, 0, TEXT("SysListView32"), TEXT("FolderView"));

	if (!HSHELLDLL_DefView)
		EnumWindows(Utilities::EnumWindowsProc, 0);

	if (desktopWindow == DW_ProgMan)
		return HProgMan;
	else if (desktopWindow == DW_SHELLDLL_DefViewParent)
		return HSHELLDLL_DefViewParent;
	else if (desktopWindow == DW_SHELLDLL_DefView)
		return HSHELLDLL_DefView;
	else if (desktopWindow == DW_SysListView32)
		return HSysListView32;
	else
		return 0;
}

BOOL CALLBACK Utilities::EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
	TCHAR className[255];
	memset(className,0,sizeof(className));
	GetClassName(hWnd,className,sizeof(className));

	if (!_tcscmp(className,TEXT("WorkerW")))
	{
		HWND child = FindWindowEx(hWnd, 0, TEXT("SHELLDLL_DefView"), 0);
		if (child)
		{
			HSHELLDLL_DefViewParent = hWnd;
			HSHELLDLL_DefView = child;
			HSysListView32 = FindWindowEx(child, 0, TEXT("SysListView32"), TEXT("FolderView")); ;
			return false;
		}
	}
	return true;
}

bool Utilities::IsSpecialWindow(HWND hWnd)
{
	TCHAR className[255]={0};
	GetClassName(hWnd,className,sizeof(className));

	if (hWnd == GetShellWindow()
		|| hWnd == GetDesktopWindow(DW_SHELLDLL_DefViewParent)
        || !_tcscmp(className, TEXT("WorkerW"))
        || !_tcscmp(className, TEXT("NotifyIconOverflowWindow"))
        || !_tcscmp(className, TEXT("DV2ControlHost"))
        || !_tcscmp(className, TEXT("Desktop User Picture"))
        || !_tcscmp(className, TEXT("Auto-Suggest Dropdown"))                    
		|| !_tcscmp(className, TEXT("Shell_TrayWnd"))
		|| !_tcscmp(className, TEXT("SynTrackCursorWindowClass"))
		|| !_tcscmp(className, TEXT("TaskListThumbnailWnd"))
		|| !_tcscmp(className, TEXT("TaskSwitcherWnd"))
		|| hWnd == FindWindow(TEXT("Button"),TEXT("Start")))
	{
        return true;
	}

	return false;
}

bool Utilities::IsValidTaskWindow(HWND hWnd, bool allowMinimized, bool allowMaximized)
{
	if (!GetParent(hWnd)
        && (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) != WS_EX_TOOLWINDOW
		&& IsWindow(hWnd)
		&& !GetWindow(hWnd, GW_OWNER)
		&& IsWindowVisible(hWnd)
		&& (!IsIconic(hWnd) || allowMinimized)
		&& (!IsZoomed(hWnd) || allowMaximized)
		&& !IsSpecialWindow(hWnd))
	{
        return true;
	}

	return false;
}

POINT Utilities::GetCursorPosition()
{
	POINT result;
	GetCursorPos(&result);

	return result;
}

HWND Utilities::TopLevelWindow(HWND hWnd)
{
	HWND window = hWnd;

	if (!(window = GetAncestor(window, GA_ROOT)))
	{
		window = hWnd;
	}

	if (window == GetShellWindow())
		window = 0;

	return window;
}

HWND Utilities::TopLevelWindowFromMousePosition()
{
	HWND windowFromMousePos=WindowFromPoint(GetCursorPosition());
    
	HWND window = windowFromMousePos;

	if (!(window = GetAncestor(window, GA_ROOT)))
	{
		window = windowFromMousePos;
	}

	if (window == GetShellWindow())
		window = 0;

	return window;
}

bool Utilities::RectContainsPoint(RECT r, POINT p)
{
	return ((p.x > r.left) && (p.x < r.right) && (p.y > r.top) && (p.y < r.bottom));
}

bool Utilities::IsTopMost(HWND hWnd)
{
	return (GetWindowLong(hWnd,GWL_EXSTYLE) & WS_EX_TOPMOST) == WS_EX_TOPMOST;
}

void Utilities::SetTopMost(HWND hWnd)
{
	SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}

void Utilities::SetNoTopMost(HWND hWnd)
{
	SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}

void Utilities::ShowHWNDInfo(HWND hWnd)
{
	TCHAR windowText[MAX_CLASS_NAME];
	memset(windowText,0,sizeof(windowText));
	GetWindowText(hWnd,windowText,sizeof(windowText));

	TCHAR className[MAX_CLASS_NAME];
	memset(className,0,sizeof(className));
	GetClassName(hWnd,className,sizeof(className));

	_tprintf(TEXT("Window %x:\n\tClassname: %s\n\tWindowTitle: %s\n\n"),hWnd,className,windowText);
}

BOOL Utilities::KillProcess(DWORD pID)
{
	BOOL result=FALSE;

	if (pID)
	{
		HANDLE hProcess=OpenProcess(PROCESS_TERMINATE,FALSE,pID);
		result = TerminateProcess(hProcess,0);
		Sleep(100);
		CloseHandle(hProcess);
	}

	return result;
}

RECT Utilities::CalcWindowRect(HWND hWnd)
{
    RECT result;

    if (IsIconic(hWnd))
    {
        WINDOWPLACEMENT windowPlacement; 
		GetWindowPlacement(hWnd, &windowPlacement);

        if ((windowPlacement.flags & WPF_RESTORETOMAXIMIZED) == WPF_RESTORETOMAXIMIZED)
        {
			result.left = windowPlacement.ptMaxPosition.x;
			result.top = windowPlacement.ptMaxPosition.y;
			result.right = result.left + GetSystemMetrics(SM_CXMAXIMIZED);
			result.bottom = result.top + GetSystemMetrics(SM_CYMAXIMIZED);
        }
        else
        {
            result = windowPlacement.rcNormalPosition;
        }
    }
    else
    {
		RECT windowRect;
		GetWindowRect(hWnd,&windowRect);
        result = windowRect;
    }

    return result;
}

HWND Utilities::GetWindowFromPointEx(POINT point)
{
	HWND windowFromPoint = WindowFromPoint(point);
	HWND parent = GetParent(windowFromPoint);
	HWND windowFromPointRoot = GetAncestor(windowFromPoint,GA_ROOT);

	ScreenToClient(parent,&point);

	HWND childFromPoint = RealChildWindowFromPoint(parent,point);
	HWND childFromPointRoot = GetAncestor(childFromPoint,GA_ROOT);

	return (childFromPoint && windowFromPointRoot == childFromPointRoot) ? childFromPoint : windowFromPoint;				
}

//call between BeginPaint and EndPaint!
void Utilities::DrawDwmCompatibleText(RECT rect, HDC hdc, LPCWSTR text, int fontSize, COLORREF dwmDisabledTextColor, DWORD format, LONG fontWeight, int glowSize, int xOffset, int yOffset)
{  

	BOOL dwmEnabled=0;
	DwmIsCompositionEnabled(&dwmEnabled);

	if (dwmEnabled)
	{
		HTHEME hTheme = OpenThemeData(NULL, L"CompositedWindow::Window");
		if (hTheme)
		{
			HDC hdcPaint = CreateCompatibleDC(hdc);
			if (hdcPaint)
			{
				int cx = RECTWIDTH(rect);
				int cy = RECTHEIGHT(rect);

				// Define the BITMAPINFO structure used to draw text.
				// Note that biHeight is negative. This is done because
				// DrawThemeTextEx() needs the bitmap to be in top-to-bottom
				// order.
				BITMAPINFO dib = { 0 };
				dib.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
				dib.bmiHeader.biWidth           = cx;
				dib.bmiHeader.biHeight          = -cy;
				dib.bmiHeader.biPlanes          = 1;
				dib.bmiHeader.biBitCount        = 32;
				dib.bmiHeader.biCompression     = BI_RGB;

				HBITMAP hbm = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
				if (hbm)
				{
					HBITMAP hbmOld = (HBITMAP)SelectObject(hdcPaint, hbm);

					// Setup the theme drawing options.
					DTTOPTS DttOpts = {sizeof(DTTOPTS)};
					DttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE;
					DttOpts.iGlowSize = glowSize;

					// Select a font.
					LOGFONT lgFont;
					HFONT hFont = 0;
					HFONT hFontOld = 0;
					if (SUCCEEDED(GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &lgFont)))
					{
						lgFont.lfHeight = -fontSize;
						lgFont.lfWeight= fontWeight;

						hFont = CreateFontIndirect(&lgFont);
						if (hFont)
							hFontOld = (HFONT) SelectObject(hdcPaint, hFont);
					}

					// Draw the title.
					RECT rcPaint = rect;
					rcPaint.top += yOffset;
					rcPaint.bottom += yOffset;
					rcPaint.left += xOffset;
					rcPaint.right += xOffset;
					DrawThemeTextEx(hTheme, hdcPaint, 0, 0, text, -1, format, &rcPaint, &DttOpts);

					// Blit text to the frame.
					BitBlt(hdc, 0, 0, cx, cy, hdcPaint, 0, 0, SRCCOPY);

					if (hFont)
					{
						SelectObject(hdcPaint, hFontOld);
						DeleteObject(hFont);
					}

					SelectObject(hdcPaint, hbmOld);
					DeleteObject(hbm);
				}
				DeleteDC(hdcPaint);
			}

			CloseThemeData(hTheme);
		}
	}
	else
	{
		DrawDefaultText(rect, hdc, text, fontSize, dwmDisabledTextColor, format, fontWeight, xOffset, yOffset);
	}
}

//call between BeginPaint and EndPaint!
void Utilities::DrawDefaultText(RECT rect, HDC hdc, LPCWSTR text, int fontSize, COLORREF textColor, DWORD format, LONG fontWeight, int xOffset, int yOffset)
{
	HTHEME hTheme = OpenThemeData(NULL, L"CompositedWindow::Window");

	if (hTheme)
	{
		// Select a font.
		LOGFONT lgFont;
		HFONT hFont = 0;
		HFONT hFontOld = 0;
		if (SUCCEEDED(GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &lgFont)))
		{
			lgFont.lfHeight = -fontSize;
			lgFont.lfWeight = fontWeight;

			hFont = CreateFontIndirect(&lgFont);
			if (hFont)
				hFontOld = (HFONT) SelectObject(hdc, hFont);
		}

		// Draw the title.
		rect.top += yOffset;
		rect.bottom += yOffset;
		rect.left += xOffset;
		rect.right += xOffset;
		SetBkMode(hdc, TRANSPARENT);
		SetTextColor(hdc, textColor);
		DrawText(hdc, text, -1, &rect, format);

		if (hFont)
		{
			SelectObject(hdc, hFontOld);
			DeleteObject(hFont);
		}

		CloseThemeData(hTheme);
	}
}

bool Utilities::EndsWith(LPCTSTR string, LPCTSTR end)
{
    int lengthString = _tcslen(string);
    int lengthEnd = _tcslen(end);
    LPCTSTR strEnd = string + lengthString - lengthEnd;

    return !_tcscmp(strEnd, end);
}

set<tstring, TStringSortTemplate> Utilities::GetDirectoryEntries(LPCTSTR lpFileName, int ft, tstring specialDirExt)
{
	set<tstring, TStringSortTemplate> result;

	WIN32_FIND_DATA ffd;
	HANDLE hFind;

	hFind = FindFirstFile(lpFileName, &ffd);

	if (hFind == INVALID_HANDLE_VALUE) 
	{
		SetLastError(ERROR_INVALID_HANDLE);
		return result;
	}
	do
	{
		if (_tcscmp(ffd.cFileName, TEXT(".")) && _tcscmp(ffd.cFileName, TEXT("..")))
		{
			tstring ts(ffd.cFileName);

			if ((ft & FT_DIRECTORY) && (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
			{
				if (specialDirExt.length() > 0)
					ts.append(specialDirExt);

				result.insert(ts);
			}
			
			if ((ft & FT_FILE) && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
					result.insert(ts);
		}
	}
	while (FindNextFile(hFind, &ffd) != 0);

	FindClose(hFind);	

	return result;
}

tstring Utilities::GetKnownFolderPath(const KNOWNFOLDERID &rfid)
{
	LPWSTR path=0;
	SHGetKnownFolderPath(rfid,0,0,&path);
	tstring sPath(path);
	CoTaskMemFree(path);

	return sPath;
}

set<tstring, TStringSortTemplate> Utilities::SplitTString(tstring str, tstring separator, bool ignoreEmptyStrings)
{
	set<tstring, TStringSortTemplate> result;

	int start = 0;
	int end = 0;

	do
	{
		end = str.find(separator, end);

		if (end != -1)
		{
			tstring s = str.substr(start, (end-start));
			
			if (!ignoreEmptyStrings || s.length() > 0)
				result.insert(s);

			start = ++end;
		}
		else
		{
			tstring s = str.substr(start);

			if (!ignoreEmptyStrings || s.length() > 0)
				result.insert(s);
		}
	}
	while (end != -1);

	return result;
}

bool Utilities::MoveWindowIntoVisibleArea(HWND hWnd)
{
	bool hasMoved=false;

	POINT pos;
	GetCursorPos(&pos);

	HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
	MONITORINFO mi;
	mi.cbSize = sizeof(MONITORINFO);

	GetMonitorInfo(monitor,&mi);

	RECT windowRect = {0};
	GetWindowRect(hWnd, &windowRect);
		
    if (windowRect.right > mi.rcWork.right)
    {
		SetWindowPos(hWnd, 0, mi.rcWork.right - RECTWIDTH(windowRect), windowRect.top, 0, 0, SWP_NOSIZE);
		windowRect.left = mi.rcWork.right - RECTWIDTH(windowRect);
    
		hasMoved=true;
    }
    if (windowRect.bottom > mi.rcWork.bottom)
    {
		SetWindowPos(hWnd, 0, windowRect.left, mi.rcWork.bottom - RECTHEIGHT(windowRect), 0, 0, SWP_NOSIZE);
        windowRect.top = mi.rcWork.bottom - RECTHEIGHT(windowRect);
    
		hasMoved=true;
    }
	if (windowRect.left < mi.rcWork.left)
    {
        SetWindowPos(hWnd, 0, mi.rcWork.left, windowRect.top, 0, 0, SWP_NOSIZE);
        windowRect.left = mi.rcWork.left;

		hasMoved=true;
    }
    if (windowRect.top < mi.rcWork.top)
    {
		SetWindowPos(hWnd, 0, windowRect.left, mi.rcWork.top, 0, 0, SWP_NOSIZE);
		windowRect.top = mi.rcWork.top;

		hasMoved=true;
    }

	return hasMoved;
}

POINT Utilities::CenterScreen(LONG cx, LONG cy, bool workingArea, bool primaryScreen)
{
	SIZE s={cx,cy};
	return CenterScreen(s, workingArea, primaryScreen);
}

POINT Utilities::CenterScreen(SIZE windowSize, bool workingArea, bool primaryScreen)
{
	POINT result;

	POINT pos={0,0};

	if (!primaryScreen)
		GetCursorPos(&pos);

	HMONITOR monitor = MonitorFromPoint(pos,MONITOR_DEFAULTTOPRIMARY);
	MONITORINFO mi;
	mi.cbSize = sizeof(MONITORINFO);

	GetMonitorInfo(monitor,&mi);

	RECT screenBounds;

	if (workingArea)
		screenBounds = mi.rcWork;
	else
		screenBounds = mi.rcMonitor;

	int screenWidth = RECTWIDTH(screenBounds);
	int screenHeight = RECTHEIGHT(screenBounds);

	result.x = screenBounds.left + screenWidth/2-windowSize.cx/2;
	result.y = screenBounds.top + screenHeight/2-windowSize.cy/2;

	return result;
}

bool Utilities::LockDrive(TCHAR cDrive, bool bLock)
{
    TCHAR lpDrive [10];
    bool bLocked = true;

    _stprintf(lpDrive, TEXT("\\\\.\\%c:"), cDrive);

    HANDLE hDevice = CreateFile (lpDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

    unsigned long dwBytesReturned = 0;
    PREVENT_MEDIA_REMOVAL pmr = {bLock};

    if (!DeviceIoControl (hDevice, IOCTL_STORAGE_MEDIA_REMOVAL, &pmr, sizeof(pmr), NULL, 0, &dwBytesReturned, NULL))
        bLocked = false;

    CloseHandle (hDevice);

    return bLocked;
}

Grid Utilities::CalculateGridArea(int count)
{
	Grid result = {0};

	double d = sqrt((double)count);

	result.Rows= (int)d;

	if (result.Rows == d)
		result.Columns = result.Rows;
	else
	{
		result.Columns = result.Rows + 1;
		if ((d - result.Rows) >= 0.5)
			result.Rows += 1;
	}

	return result;
}

void Utilities::CreateRoundRectPath(GraphicsPath* path, RECT rect, int radius, int offset)
{
	CreateRoundRectPath(path, rect, radius, radius, radius, radius, offset, offset, offset, offset);
}

void Utilities::CreateRoundRectPath(GraphicsPath* path, RECT rect, int radiusTopLeft, int radiusTopRight, int radiusBottomRight, int radiusBottomLeft, int offset)
{
	CreateRoundRectPath(path, rect, radiusTopLeft, radiusTopRight, radiusBottomRight, radiusBottomLeft, offset, offset, offset, offset);
}

void Utilities::CreateRoundRectPath(GraphicsPath* path, RECT rect, int radiusTopLeft, int radiusTopRight, int radiusBottomRight, int radiusBottomLeft, int offsetLeft, int offsetTop, int offsetRight, int offsetBottom)
{
	offsetLeft *= -1;
	offsetTop *= -1;
	offsetRight *= -1;
	offsetBottom *= -1;

	path->Reset();
	path->StartFigure();

	path->AddLine(rect.left + radiusTopLeft + offsetLeft, rect.top + offsetTop, rect.right - radiusTopRight - offsetRight, rect.top + offsetTop);
	path->AddArc(rect.right - radiusTopRight - offsetRight - 1, rect.top + offsetTop, radiusTopRight, radiusTopRight, 270, 90);

	path->AddLine(rect.right - offsetRight - 1, rect.top + radiusTopRight + offsetTop, rect.right - offsetRight - 1, rect.bottom - radiusBottomRight - offsetBottom);
	path->AddArc(rect.right - radiusBottomRight - offsetRight - 1, rect.bottom - radiusBottomRight - offsetBottom - 1, radiusBottomRight, radiusBottomRight, 0, 90);

	path->AddLine(rect.right - radiusBottomRight - offsetRight - 1, rect.bottom - offsetBottom - 1, rect.left + radiusBottomLeft + offsetLeft, rect.bottom - offsetBottom - 1);
	path->AddArc(rect.left + offsetLeft, rect.bottom - radiusBottomLeft - offsetBottom - 1, radiusBottomLeft, radiusBottomLeft, 90, 90);

	path->AddLine(rect.left + offsetLeft, rect.bottom - radiusBottomLeft - offsetBottom - 1, rect.left + offsetLeft, rect.top + radiusTopLeft + offsetTop);
	path->AddArc(rect.left + offsetLeft, rect.top + offsetTop, radiusTopLeft, radiusTopLeft, 180, 90);

	path->CloseFigure();
}


void Utilities::DrawPNGFromResource(HINSTANCE hInstance, HDC hdc, LPCTSTR resourceName, int x, int y, int width, int height)
{
	HRSRC hRsrc;

	if (hRsrc = FindResource(hInstance, resourceName, TEXT("PNG")))
	{
		HGLOBAL hImage;

		if (hImage = LoadResource(hInstance, hRsrc))
		{
			LPVOID pImage;

			if (pImage = LockResource(hImage))
			{
				HGLOBAL hBlock;

				int size = SizeofResource(hInstance, hRsrc);

				if (hBlock = GlobalAlloc(GHND, size))
				{
					LPVOID pBlock;

					if (pBlock = GlobalLock(hBlock))
					{
						IStream* pStream;

						memmove(pBlock, pImage, size);

						if (CreateStreamOnHGlobal(hBlock, FALSE, &pStream) == S_OK)
						{
							Graphics graphics(hdc);
							Image image(pStream);

							graphics.DrawImage(&image, x, y, width, height);

							pStream->Release();
						}

						GlobalUnlock(hBlock);
					}

					GlobalFree(hBlock);
				}
			}
		}
	}
}

HICON Utilities::GetSmallWindowIcon(HWND hWnd)
{
	HICON hIcon = (HICON)SendMessage(hWnd, WM_GETICON, ICON_SMALL2, 0);

	if (!hIcon)
		hIcon = (HICON)GetClassLongPtr(hWnd, GCL_HICON);

	if (!hIcon)
		hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));

	return hIcon;
}

bool Utilities::IsSpecialCassiopeiaWindow(HWND hWnd)
{
	TCHAR className[255]={0};
	GetClassName(hWnd,className,sizeof(className));

	if (!_tcscmp(className, TEXT("DeskNotesWindow"))
		|| !_tcscmp(className, TEXT("DeskTidyWindow"))
		|| !_tcscmp(className, TEXT("WindowGroupsWindow"))
		|| !_tcscmp(className, TEXT("DesktopPictureFrame"))
		|| !_tcscmp(className, TEXT("QuickButtonsWindow")))
	{
        return true;
	}
	
	return false;
}

HWND Utilities::GetLastValidTopLevelWindow()
{	
	HWND last = GetWindow(Utilities::GetDesktopWindow(Utilities::DW_SHELLDLL_DefViewParent), GW_HWNDPREV);

	while ((!IsWindow(last)
		|| !IsWindowVisible(last)
		|| IsIconic(last)
		|| IsSpecialWindow(last)
		|| IsSpecialCassiopeiaWindow(last))
		&& last)
	{
		last=GetWindow(last, GW_HWNDPREV);
	}

	return last;
}

tstring Utilities::GetWindowFileName(HWND hWnd)
{
	TCHAR fileName[_MAX_PATH - 1] = {0};
	TCHAR longFileName[_MAX_PATH - 1] = {0};
	DWORD size = sizeof(fileName)/sizeof(TCHAR);

	DWORD pid = 0;
	GetWindowThreadProcessId(hWnd, &pid);

	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
	QueryFullProcessImageName(hProcess, 0, fileName, &size);
	GetLongPathName(fileName, longFileName, sizeof(longFileName)/sizeof(TCHAR));
	CloseHandle(hProcess);

	tstring result(longFileName);

	return result;
}

TCHAR Utilities::GetVolumeLetter(DWORD mask)
{
	int i = 0;
	for (i = 0; i < 26; ++i)
	{
		if ((mask & 0x1) == 0x1) break;
		mask >>= 1;
	}
	return (i + 'A');
}

DWORD Utilities::GetVolumeSerial(TCHAR volumeLetter)
{
	TCHAR volumeName[_MAX_PATH] = {0};
	TCHAR fileSystemName[_MAX_PATH] = {0};

	DWORD volumeSerialNumber = 0;
	DWORD maxComponentLength = 0;
	DWORD fileSystemFlags = 0;

	TCHAR drive[] = {volumeLetter, ':', '\\', '\0'};
	GetVolumeInformation(drive, volumeName, sizeof(volumeName), &volumeSerialNumber, &maxComponentLength, &fileSystemFlags, fileSystemName, sizeof(fileSystemName));

	return volumeSerialNumber;
}

tstring Utilities::GetVolumeName(TCHAR volumeLetter)
{
	TCHAR volumeName[_MAX_PATH] = {0};
	TCHAR fileSystemName[_MAX_PATH] = {0};

	DWORD volumeSerialNumber = 0;
	DWORD maxComponentLength = 0;
	DWORD fileSystemFlags = 0;

	TCHAR drive[] = {volumeLetter, ':', '\\', '\0'};
	GetVolumeInformation(drive, volumeName, sizeof(volumeName), &volumeSerialNumber, &maxComponentLength, &fileSystemFlags, fileSystemName, sizeof(fileSystemName));

	tstring result(volumeName);

	if (result.length() > 0)
	{
		return result;
	}
	else
	{
		tstring driveRoot(drive);
		return driveRoot;
	}
}

set<TCHAR> Utilities::GetDrives(int driveType)
{
	set<TCHAR> drives;
	DWORD logicalDrives = GetLogicalDrives();

	for (int drive = 0; drive < 32; drive++)
	{
		if (logicalDrives & (1 << drive))
		{
			TCHAR volumeLetter = drive + 'A';
			TCHAR driveRoot[] = {volumeLetter, ':', '\\', '\0'};
			
			int i = GetDriveType(driveRoot);

			if (driveType == -1 || GetDriveType(driveRoot) == driveType)
				drives.insert(volumeLetter);
		}
	}

	return drives;
}

bool Utilities::ExistsFile(tstring fileName)
{
	ifstream file(fileName.c_str());
	return file;
}

int Utilities::GetEncoderClsid(tstring format, CLSID* pClsid)
{
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	ImageCodecInfo* pImageCodecInfo = 0;

	GetImageEncodersSize(&num, &size);
	if(!size)
		return -1;  // Failure

	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(!pImageCodecInfo)
		return -1;  // Failure

	GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if(!_tcscmp(pImageCodecInfo[j].MimeType, format.c_str()))
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}    
	}

	free(pImageCodecInfo);
	return -1;  // Failure
}

bool Utilities::IsWindowHanging(HWND hWnd)
{
	if (SendMessageTimeout(hWnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 1000, 0))
		return false;
	else
		return true;
}

tstring Utilities::ConvertToString(int value)
{
	TCHAR text[200];		
	_stprintf(text, TEXT("%d"), value);
	return text;
}